package Server;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.DoublePredicate;

public class KmeansCluster {
	private List<point> dataArray;//待分类的原始值  
	private int K = 3;//将要分成的类别个数  
	private int maxClusterTimes = 500;//最大迭代次数  
	private Map<Integer,List<point>> clusterMap;//聚类的结果  
	private List<Double[]> clusteringCenter;//质心
	private double threshold = 0.000001; 
	
	public void init(List<point> datasource,int k,int maxtimes,double thres){
		setDataArray(datasource);
		setK(k);
		setMaxClusterTimes(maxtimes);
		setThreshold(thres);
	}


	public int getMaxClusterTimes() {
		return maxClusterTimes;
	}

	public void setMaxClusterTimes(int maxClusterTimes) {
		this.maxClusterTimes = maxClusterTimes;
	}

	

	public int getK() {
		return K;
	}

	public void setK(int k) {
		K = k;
	}


	public List<point> getDataArray() {
		return dataArray;
	}


	public void setDataArray(List<point> dataArray) {
		this.dataArray = dataArray;
	}

	public List<Double[]> getClusteringCenter() {
		return clusteringCenter;
	}


	public void setClusteringCenter(List<Double[]> clusteringCenter) {
		this.clusteringCenter = clusteringCenter;
	}


	public Map<Integer,List<point>> getClusterMap() {
		return clusterMap;
	}


	public void setClusterMap(Map<Integer,List<point>> clusterMap) {
		this.clusterMap = clusterMap;
	}


	public double getThreshold() {
		return threshold;
	}


	public void setThreshold(double threshold) {
		this.threshold = threshold;
	}
	
	//计算点与聚类中心的距离
	private double countDistance(Double[] point,Double[] center){
		double result = 0;
		for(int i = 0;i<point.length;i++){
			result+=(point[i] - center[i])*(point[i] - center[i]);
		}
		result = Math.sqrt(result);
		return result;
	}
	
	//计算聚类中心
	private Double[] getCenter(List<point> list){
		int i = list.size();	//点的个数
		int weidu = list.get(0).getPoint().length;
		double[] result = new double[weidu];
		Double[] finalresult = new Double[weidu];
		for(point p:list){
			Double[] pDoubles = p.getPoint();
			for(int j = 0;j < weidu;j++){
				
				result[j]+=pDoubles[j];
			}
		}
		for(int j = 0;j<weidu;j++){
			result[j] = result[j]/i; 
			finalresult[j] = Double.valueOf(result[j]);
		}
		return finalresult;
	}
	
	//判断聚类中心是否改变超过阈值
	private boolean isCenterMove(List<Double[]> preCenter,List<Double[]> nowCenter){
		for(int i = 0;i < preCenter.size();i++){
			if(countDistance(preCenter.get(i), nowCenter.get(i))>this.threshold){
				return true;
			}
		}
		return false;
	}
	//最初随机抽取K个点作为聚类中心
	private void randomClusteringCenter(){
		List<Integer> clusteringCenterId = new ArrayList<>();
		List<point> clusteringCenter = new ArrayList<>();
		for(;clusteringCenterId.size()<this.K;){
			int num = (int) (Math.random() * this.dataArray.size());
			for(int i=0;i<clusteringCenter.size();i++){
				if(clusteringCenterId.get(i)==num){
					clusteringCenterId.remove(i);
				}
			}
			clusteringCenterId.add(num);
		}
		for(int i = 0;i<this.K;i++){
			clusteringCenter.add(this.dataArray.get(clusteringCenterId.get(i)));
		}
		List<Double[]> center = new ArrayList<>();
		for(point p:clusteringCenter){
			center.add(p.getPoint());
		}
		this.clusteringCenter = center;
		System.out.println("----------------初始质心已生成----------------");
	}
	
	
	//聚类
	private void clustering(List<Double []>preCenter,int times){
		System.out.println("times:"+times);
		if(preCenter==null){
			System.out.println("聚类中心不存在");
			return;
		}
		Map<Integer,List<point>> clusterMap = new HashMap<>();
		for(point p:dataArray){			//计算每个点最近的聚类中心
			Double[] point = p.getPoint();
			double mindistance = countDistance(point, preCenter.get(0));
			int num = 0;
			for(int i = 1;i < preCenter.size();i++){
				double thisdistance = countDistance(point, preCenter.get(i));
				if(mindistance > thisdistance){
					mindistance = thisdistance;
					num = i;
				}
			}
			if(clusterMap.containsKey(num)){
				List<point> templist = clusterMap.get(num);
				templist.add(p);
			}
			else {
				List<point> templist = new ArrayList<>();
				templist.add(p);
				clusterMap.put(num, templist);
			}
		}
		List<Double[]> nowCenter = new ArrayList<>();	//新的聚类中心
		List<Integer> mapnum = new ArrayList<>();		//map的key排序，用于顺序遍历
		for(Integer integer:clusterMap.keySet()){
			mapnum.add(integer);
		}
		Collections.sort(mapnum);
		for(Integer integer:mapnum){
			nowCenter.add(getCenter(clusterMap.get(integer)));
		}
		if(times>this.maxClusterTimes){
			this.clusterMap = clusterMap;
			return;
		}
		this.clusteringCenter = nowCenter;
		
		if (isCenterMove(preCenter, nowCenter)) {  
			clusterMap.clear();
	        clustering(nowCenter, times + 1);  
	    } else {  
	        this.clusterMap = clusterMap;  
	    }  
	}
	
	public void kmClustering(){
		if(dataArray.isEmpty()){
			System.out.println("----------------未完成初始化----------------");
			return;
		}
		randomClusteringCenter();
		clustering(clusteringCenter, 0);
		System.out.println("----------------聚类已完成----------------");
	}

	public List<String> getKMclusteringResult(){
		List<String> resultlist = new ArrayList<>();
		List<String> telecomorder = IOHandler.readAsList(new File("D:/workspace/HotEventMonitoring/2017年1月-2017年12月嘉兴的单子信息/save.txt"));
		Map<String, String> predata = new HashMap<>();
		for(String line:telecomorder){
			String[] temp = line.split("\\+\\+");
			System.out.println(temp[0]+"+"+temp[1]);
			predata.put("#"+temp[0], temp[1]);
		}
		KmeansCluster kmeansCluster = new KmeansCluster();
		List<point> datasorce = new ArrayList<>();
		List<String> readfile = IOHandler.readAsList(new File("D:/workspace/HotEventMonitoring/2017年1月-2017年12月嘉兴的单子信息/features.txt"));
		for(int i=0;i<readfile.size();i=i+2){
			point p = new point();
			p.setId(readfile.get(i));
			String[] value = readfile.get(i+1).split(",");
			Double[] pDouble = new Double[value.length];
			for(int j = 0;j<pDouble.length;j++){
				pDouble[j] = Double.valueOf(value[j]);
			}
			p.setPoint(pDouble);
			datasorce.add(p);
		}
		
		kmeansCluster.init(datasorce, 100, 100, 0.01);
		kmeansCluster.kmClustering();
		List<String> finalresultlist = new ArrayList<>();
		Map<Integer,List<point>> clusterMap = kmeansCluster.getClusterMap();
		String []printkey = {"0","1","2","3","4"};
		int [] number = {0,0,0,0,0};
		for(Map.Entry<Integer, List<point>> entry:clusterMap.entrySet()){
			int minnum = 0;
			for(int i = 1;i<5;i++){
				if(number[i]<number[minnum]){
					minnum = i;
				}
			}
			if(entry.getValue().size()>number[minnum]){
				printkey[minnum] = ""+entry.getKey();
				number[minnum] = entry.getValue().size();
			}
		}
		for(Map.Entry<Integer, List<point>> entry:clusterMap.entrySet()){
			resultlist.add("#"+entry.getKey());
			for(point p:entry.getValue()){
				resultlist.add(p.getId()+"||"+predata.get(p.getId()));
			}
			IOHandler.serialize2File(resultlist, new File("D:/workspace/HotEventMonitoring/2017年1月-2017年12月嘉兴的单子信息/km2.txt"));
		}
		for(int i = 0;i<5;i++){
			int key = Integer.parseInt(printkey[i]);
			List<point> pointlist = clusterMap.get(key);
			String printstring = "聚类编号"+printkey[i]+": ";
			for(point p:pointlist){
				printstring+=(p.getId()+" ");
			}
			finalresultlist.add(printstring);
		}
		return finalresultlist;
	}
	
	public static void main(String[] args) {
		List<String> telecomorder = IOHandler.readAsList(new File("D:/workspace/HotEventMonitoring/2017年1月-2017年12月嘉兴的单子信息/save.txt"));
		Map<String, String> predata = new HashMap<>();
		for(String line:telecomorder){
			String[] temp = line.split("\\+\\+");
			System.out.println(temp[0]+"+"+temp[1]);
			predata.put("#"+temp[0], temp[1]);
		}
		KmeansCluster kmeansCluster = new KmeansCluster();
		List<point> datasorce = new ArrayList<>();
		List<String> readfile = IOHandler.readAsList(new File("D:/workspace/HotEventMonitoring/2017年1月-2017年12月嘉兴的单子信息/features.txt"));
		for(int i=0;i<readfile.size();i=i+2){
			point p = new point();
			p.setId(readfile.get(i));
			String[] value = readfile.get(i+1).split(",");
			Double[] pDouble = new Double[value.length];
			for(int j = 0;j<pDouble.length;j++){
				pDouble[j] = Double.valueOf(value[j]);
			}
			p.setPoint(pDouble);
			datasorce.add(p);
		}
		/*for(point p:datasorce){
			System.out.println("#"+p.getId());
			String line = "";
			for(Double d:p.getPoint()){
				line+=d+",";
			}
			System.out.println(line);
		}*/
		kmeansCluster.init(datasorce, 100, 100, 0.01);
		kmeansCluster.kmClustering();
		List<String> resultlist = new ArrayList<>();
		Map<Integer,List<point>> clusterMap = kmeansCluster.getClusterMap();
		String []printkey = {"0","1","2","3","4"};
		int [] number = {0,0,0,0,0};
		for(Map.Entry<Integer, List<point>> entry:clusterMap.entrySet()){
			int minnum = 0;
			for(int i = 1;i<5;i++){
				if(number[i]<number[minnum]){
					minnum = i;
				}
			}
			if(entry.getValue().size()>number[minnum]){
				printkey[minnum] = ""+entry.getKey();
				number[minnum] = entry.getValue().size();
			}
		}
		for(Map.Entry<Integer, List<point>> entry:clusterMap.entrySet()){
			resultlist.add("#"+entry.getKey());
			for(point p:entry.getValue()){
				resultlist.add(p.getId()+"||"+predata.get(p.getId()));
			}
			IOHandler.serialize2File(resultlist, new File("D:/workspace/HotEventMonitoring/2017年1月-2017年12月嘉兴的单子信息/km2.txt"));
		}
		for(int i = 0;i<5;i++){
			int key = Integer.parseInt(printkey[i]);
			List<point> pointlist = clusterMap.get(key);
			String printstring = printkey[i];
			for(point p:pointlist){
				printstring+=(p.getId()+"||");
			}
			System.out.println(printstring);
		}
	}
}
